{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Topic 2, Part 2 - CPA on Hardware AES Implementation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *By now you should have a pretty good understanding of how software implementations of AES are vulnerable to CPA attacks. You might be wondering: are hardware implementations of AES also vulnerable to CPA attacks?*\n",
    "\n",
    "*In this lab, we'll perform a CPA attack on the hardware AES implementation in the STM32F415. We'll also introduce LASCAR for increased performance when analyzing large datasets.*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "* Understanding how leakage differs between software AES and hardware AES implementations\n",
    "* Using LASCAR for CPA attacks\n",
    "* Identifying different leakage points"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Capture traces as normal. We'll need to select the HWAES crypto target instead of TINYAES or MBEDTLS. Also we don't need to capture as many traces - the whole AES block will fit in less than 2000 traces. We'll also boost the gain a little bit - HWAES won't result in as big of power spikes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CW308_STM32F4'\n",
    "VERSION = 'HARDWARE'\n",
    "SS_VER = 'SS_VER_2_1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    from lascar import *\n",
    "except Exception as e:\n",
    "    raise ImportError(\"You need to install lascar at https://github.com/Ledger-Donjon/lascar\") from e"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "CRYPTO_TARGET = 'HWAES' # overwrite auto inserted CRYPTO_TARGET"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if VERSION == 'HARDWARE':\n",
    "    %run \"Lab 2_2 - CPA on Hardware AES Implementation (HARDWARE).ipynb\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introducing LASCAR\n",
    "\n",
    "With how many traces we're capturing, analyzing our traces will take a lot of time with ChipWhisperer - Analyzer wasn't designed for performance. It is for this reason that we will be using LASCAR, an open source side channel analysis library with a bigger emphasis on speed than ChipWhisperer Analyzer. Normally, it would take a bit of work to massage ChipWhisperer into the LASCAR format; however, ChipWhisperer has recently integrated some basic LASCAR support, making it easy to combine LASCAR and ChipWhisperer projects! Note that this support is a WIP and not offically documented - the interface can change at any time!\n",
    "\n",
    "Basic setup is as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer.common.api.lascar as cw_lascar\n",
    "from lascar import *\n",
    "cw_container = cw_lascar.CWContainer(project, project.textouts, end=1000) #optional start and end args set start and end points for analysis\n",
    "guess_range = range(256)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Leakage Model\n",
    "\n",
    "Thus far, we've been exclusively focusing on software AES. Here, each AES operation (shift rows, add round key, mix columns, etc) is implemented using one basic operation (XOR, reads/writes, multiplies, etc.) per clock cycle. With a hardware implementation, it's often possible to not only combine basic operations into a block that can run in a single clock cycle, but also combine multiple AES operations and run them in a single block! For example, the CW305 FPGA board can run each round of AES in a single clock cycle!\n",
    "\n",
    "Because of this, running a CPA attack on hardware AES is much trickier than on software AES. In software, we found that it was easy to search for the outputs of the s-boxes because these values would need to be loaded from memory onto a high-capacitance data bus. This is not necessarily true for hardware AES, where the output of the s-boxes may be directly fed into the next stage of the algorithm. In general, we may need some more knowledge of the hardware implementation to successfully complete an attack. That being said, if we take a look at a block diagram of AES:\n",
    "\n",
    "![](img/AES_Encryption.png)\n",
    "\n",
    "the last round jumps out for a few reasons:\n",
    "\n",
    "* It's not far removed from the ciphertext or the plaintext\n",
    "* It's got an AddRoundKey and a SubBytes, meaning we get a nonlinear addition of the key between the ciphertext and the input of the round\n",
    "* There's no Mix Columns\n",
    "\n",
    "Let's make a guess at the implementation and say that it'll do the last round in a single clock cycle and store the input and output in the same memory block. Our reset assumption that allowed us to simply use the Hamming weight instead of the Hamming distance also probably won't be valid here. As such, let's use the Hamming distance between the output and the input of the last round.\n",
    "\n",
    "ChipWhisperer now includes a few leakage models for use with LASCAR:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "leakage = cw_lascar.lastround_HD_gen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, we can actually run the analysis. It should chew through our 15k traces in only a minute or two!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cpa_engines = [CpaEngine(\"cpa_%02d\" % i, leakage(i), guess_range) for i in range(16)]\n",
    "session = Session(cw_container, engines=cpa_engines).run(batch_size=50)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's print out our results and plot the correlation of our guesses:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer.analyzer as cwa\n",
    "plt = cw.plot([])\n",
    "key_guess = []\n",
    "last_round_key = cwa.aes_funcs.key_schedule_rounds(list(project.keys[0]),0,10)\n",
    "#actual = last_round_key\n",
    "\n",
    "for i in range(16):\n",
    "    results = cpa_engines[i].finalize()\n",
    "    guess = abs(results).max(1).argsort()[-1]\n",
    "    guess2 = abs(results).max(1).argsort()[-2]\n",
    "    print(\"Best Guess is {:02X} (Corr = {})\".format(guess, abs(results).max()))\n",
    "    actual = last_round_key[i]\n",
    "    if guess != actual:\n",
    "        plt *= cw.plot(results[guess]).opts(color='green')\n",
    "    else:\n",
    "        plt *= cw.plot(results[guess2]).opts(color='green')\n",
    "    plt *= cw.plot(results[actual]).opts(color='red')\n",
    "    key_guess.append(guess)\n",
    "\n",
    "    \n",
    "plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ChipWhisperer also includes a class to interpret the results of the analysis:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer.analyzer as cwa\n",
    "last_round_key = cwa.aes_funcs.key_schedule_rounds(list(project.keys[0]),0,10)\n",
    "disp = cw_lascar.LascarDisplay(cpa_engines, last_round_key)\n",
    "disp.show_pge()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Interestingly, you should see that the attack has worked fairly well for most of the bytes. All of them, in fact, except bytes 0, 4, 8, and 12. Looking the correlation plot, you should see two large spikes instead of one like you might expect. Try focusing the attack on either one of these points by adjusting `start=` and `end=` when making the `cw_container` and try answering the following questions:\n",
    "\n",
    "* Which spike was our expected leakage actually at (last round state diff)?\n",
    "* How might you be able to tell that the attack failed for certain bytes at the incorrect leakage point?\n",
    "* Why might this other spike be occuring?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pge_avg = 0\n",
    "for i in range(16):\n",
    "    pge_avg += disp.results().calc_PGE(i)\n",
    "    \n",
    "pge_avg /= 16\n",
    "assert pge_avg < 5, \"PGE AVG: {}\".format(pge_avg)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
